package biz.datalk.industrialland.admin.modules.system.operator.impl;

import biz.datalk.industrialland.admin.modules.system.operator.SysDictAndItemCacheManager;
import biz.datalk.industrialland.admin.modules.system.operator.SysDictAndItemOperator;
import biz.datalk.industrialland.common.def.CommonConstant;
import biz.datalk.industrialland.common.util.I18NUtil;
import biz.datalk.industrialland.common.util.RedisUtil;
import biz.datalk.industrialland.mbg.pojo.po.SysDict;
import biz.datalk.industrialland.mbg.pojo.po.SysDictItem;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Priority;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 系统数据字典与字典条目缓存管理器-基础实现
 *
 * @author ZhouYi
 * @date 2020/6/10 14:24
 * @description description
 * @note note
 */
@Priority(CommonConstant.INITIAL_PRIORITY)
@Component("sysDictAndItemCacheManagerBasicImpl")
public class SysDictAndItemCacheManagerBasicImpl implements SysDictAndItemCacheManager {

    // ===== ===== ===== ===== [常量] ===== ===== ===== ===== //

    /** 缓存的Key前缀-字典ID与字典定义缓存 */
    public static final String PREFIX_ID_AND_DICT = "id-and-dict-def:";

    /** 缓存的Key前缀-字典码与字典定义缓存 */
    public static final String PREFIX_CODE_AND_DICT = "code-and-dict-def:";

    /** 缓存的Key前缀-字典ID与字典条目List缓存 */
    public static final String PREFIX_ID_AND_DICT_ITEM_LIST = "id-and-dict-item-list:";

    /** 缓存的Key前缀-字典码与字典条目List缓存 */
    public static final String PREFIX_CODE_AND_DICT_ITEM_LIST = "code-and-dict-item-list:";

    /** 缓存的Key前缀-字典ID与字典条目Map缓存 */
    public static final String PREFIX_ID_AND_DICT_ITEM_MAP = "id-and-dict-item-map:";

    /** 缓存的Key前缀-字典码与字典条目Map缓存 */
    public static final String PREFIX_CODE_AND_DICT_ITEM_MAP = "code-and-dict-item-map:";

    // ===== ===== ===== ===== [静态变量] ===== ===== ===== ===== //


    // ===== ===== ===== ===== [成员变量] ===== ===== ===== ===== //

    /** Redis操作工具对象 */
    @Resource
    private RedisUtil redisUtil;

    /** 系统数据字典与字典条目操作器 */
    @Resource
    private SysDictAndItemOperator sysDictAndItemOperator;

    // ===== ===== ===== ===== [操作方法-全局操作] ===== ===== ===== ===== //

    @Override
    public Long clearAll() {
        // STEP Number 声明相关变量
        long removedCount = 0L;

        // STEP Number 执行清理操作
        removedCount += redisUtil.delByKeyPattern(PREFIX_ID_AND_DICT + "*");
        removedCount += redisUtil.delByKeyPattern(PREFIX_CODE_AND_DICT + "*");
        removedCount += redisUtil.delByKeyPattern(PREFIX_ID_AND_DICT_ITEM_LIST + "*");
        removedCount += redisUtil.delByKeyPattern(PREFIX_CODE_AND_DICT_ITEM_LIST + "*");
        removedCount += redisUtil.delByKeyPattern(PREFIX_ID_AND_DICT_ITEM_MAP + "*");
        removedCount += redisUtil.delByKeyPattern(PREFIX_CODE_AND_DICT_ITEM_MAP + "*");

        // STEP Number 返回执行结果
        return removedCount;

    }

    // ===== ===== ===== ===== [操作方法-数据字典定义相关] ===== ===== ===== ===== //

    @Override
    public SysDict getSysDict(String dictId, String dictCode) {
        // STEP Number 校验传入参数
        boolean[] checkingResult = checkDictIdAndDictCode(dictId, dictCode);
        boolean isDictIdNotEmpty = checkingResult[0];
        boolean isDictCodeNotEmpty = checkingResult[1];

        // STEP Number 声明相关变量
        SysDict sysDict = null;

        // STEP Number 获取缓存结果
        if (isDictIdNotEmpty) {
            sysDict = (SysDict) redisUtil.get(PREFIX_ID_AND_DICT + dictId);

        }
        if ((sysDict == null) && isDictCodeNotEmpty) {
            sysDict = (SysDict) redisUtil.get(PREFIX_CODE_AND_DICT + dictCode);

        }
        if (sysDict == null) {
            // SUBSTEP Number 从数据库中执行查询
            sysDict = sysDictAndItemOperator.getSysDict(dictId, dictCode);

            // SUBSTEP Number 如果查询结果存在，则置入缓存
            if (sysDict != null) {
                redisUtil.set(PREFIX_ID_AND_DICT + sysDict.getDictId(), sysDict, 2L, TimeUnit.HOURS);
                redisUtil.set(PREFIX_CODE_AND_DICT + sysDict.getDictCode(), sysDict, 2L, TimeUnit.HOURS);
            }

        }

        // STEP Number 返回获取到的结果
        return sysDict;

    }

    @Override
    public Long removeSysDictCacheGroup(String dictId, String dictCode) {
        // STEP Number 校验传入参数
        checkDictIdAndDictCode(dictId, dictCode);

        // STEP Number 声明相关变量
        long removedCount = 0L;

        // STEP Number 获取字典定义并校验
        SysDict sysDict = getSysDict(dictId, dictCode);
        if (sysDict == null) {
            return 0L;

        }
        dictId = sysDict.getDictId();
        dictCode = sysDict.getDictCode();

        // STEP Number 执行清理操作
        removedCount += redisUtil.del(PREFIX_ID_AND_DICT + dictId);
        removedCount += redisUtil.del(PREFIX_ID_AND_DICT_ITEM_LIST + dictId);
        removedCount += redisUtil.del(PREFIX_ID_AND_DICT_ITEM_MAP + dictId);
        removedCount += redisUtil.del(PREFIX_CODE_AND_DICT + dictCode);
        removedCount += redisUtil.del(PREFIX_CODE_AND_DICT_ITEM_LIST + dictCode);
        removedCount += redisUtil.del(PREFIX_CODE_AND_DICT_ITEM_MAP + dictCode);

        // STEP Number 返回执行结果
        return removedCount;

    }

    @Override
    public Long batchRemoveSysDictCacheGroup(List<String> dictIdList, List<String> dictCodeList) {
        // STEP Number 校验传入参数
        boolean[] checkingResult = checkDictIdListAndDictCodeList(dictIdList, dictCodeList);
        boolean isDictIdListNotEmpty = checkingResult[0];
        boolean isDictCodeListNotEmpty = checkingResult[1];

        // STEP Number 声明相关变量
        long removedCount = 0L;

        // STEP Number 循环执行清理
        if (isDictIdListNotEmpty) {
            for (String dictId : dictIdList) {
                removedCount += removeSysDictCacheGroup(dictId, null);

            }

        }
        if (isDictCodeListNotEmpty) {
            for (String dictCode : dictCodeList) {
                removedCount += removeSysDictCacheGroup(null, dictCode);

            }

        }

        // STEP Number 返回执行结果
        return removedCount;

    }

    // ===== ===== ===== ===== [操作方法-数据字典条目相关] ===== ===== ===== ===== //

    @Override
    public List<SysDictItem> getSysDictItemList(String dictId, String dictCode) {
        // STEP Number 校验传入参数
        checkDictIdAndDictCode(dictId, dictCode);

        // STEP Number 声明相关变量
        List<SysDictItem> dictItemList = null;

        // STEP Number 获取字典定义并校验
        SysDict sysDict = getSysDict(dictId, dictCode);
        if (sysDict == null) {
            return null;

        }
        dictId = sysDict.getDictId();
        dictCode = sysDict.getDictCode();

        // STEP Number 获取缓存结果
        dictItemList = toDictItemList(redisUtil.lGetAll(PREFIX_ID_AND_DICT_ITEM_LIST + dictId));
        if (CollectionUtils.isEmpty(dictItemList)) {
            dictItemList = toDictItemList(redisUtil.lGetAll(PREFIX_CODE_AND_DICT_ITEM_LIST + dictCode));

        }
        if (CollectionUtils.isEmpty(dictItemList)) {
            // SUBSTEP Number 从数据库中执行查询
            dictItemList = sysDictAndItemOperator.getSysDictItemList(dictId, dictCode);

            // SUBSTEP Number 如果查询结果存在，则置入缓存
            if (!(CollectionUtils.isEmpty(dictItemList))) {
                redisUtil.lSetAll(PREFIX_ID_AND_DICT_ITEM_LIST + dictId, dictItemList);
                redisUtil.lSetAll(PREFIX_CODE_AND_DICT_ITEM_LIST + dictCode, dictItemList);

                Map<String, String> dictItemMap = sysDictAndItemOperator.extractSysDictItemMap(dictItemList);
                redisUtil.hmSet(PREFIX_ID_AND_DICT_ITEM_MAP + dictId, dictItemMap);
                redisUtil.hmSet(PREFIX_CODE_AND_DICT_ITEM_MAP + dictCode, dictItemMap);

            }

        }

        // STEP Number 返回获取到的结果
        return dictItemList;

    }

    @Override
    public Map<String, String> getSysDictItemMap(String dictId, String dictCode) {
        // STEP Number 校验传入参数
        checkDictIdAndDictCode(dictId, dictCode);

        // STEP Number 声明相关变量
        Map<String, String> dictItemMap = null;

        // STEP Number 获取字典定义并校验
        SysDict sysDict = getSysDict(dictId, dictCode);
        if (sysDict == null) {
            return null;

        }
        dictId = sysDict.getDictId();
        dictCode = sysDict.getDictCode();

        // STEP Number 获取缓存结果
        dictItemMap = toStringMap(redisUtil.hmGet(PREFIX_ID_AND_DICT_ITEM_MAP + dictId));
        if (MapUtils.isEmpty(dictItemMap)) {
            dictItemMap = toStringMap(redisUtil.hmGet(PREFIX_CODE_AND_DICT_ITEM_MAP + dictCode));

        }
        if (MapUtils.isEmpty(dictItemMap)) {
            // SUBSTEP Number 从数据库中执行查询
            dictItemMap = sysDictAndItemOperator.getSysDictItemMap(dictId, dictCode);

            // SUBSTEP Number 如果查询结果存在，则置入缓存
            if (MapUtils.isNotEmpty(dictItemMap)) {
                redisUtil.hmSet(PREFIX_ID_AND_DICT_ITEM_MAP + dictId, dictItemMap);
                redisUtil.hmSet(PREFIX_CODE_AND_DICT_ITEM_MAP + dictCode, dictItemMap);

            }

        }

        // STEP Number 返回获取到的结果
        return dictItemMap;

    }

    @Override
    public Long removeSysDictItemCacheGroup(String dictId, String dictCode) {
        // STEP Number 校验传入参数
        checkDictIdAndDictCode(dictId, dictCode);

        // STEP Number 声明相关变量
        long removedCount = 0L;

        // STEP Number 获取字典定义并校验
        SysDict sysDict = getSysDict(dictId, dictCode);
        if (sysDict == null) {
            return 0L;

        }
        dictId = sysDict.getDictId();
        dictCode = sysDict.getDictCode();

        // STEP Number 执行清理操作
        removedCount += redisUtil.del(PREFIX_ID_AND_DICT_ITEM_LIST + dictId);
        removedCount += redisUtil.del(PREFIX_ID_AND_DICT_ITEM_MAP + dictId);
        removedCount += redisUtil.del(PREFIX_CODE_AND_DICT_ITEM_LIST + dictCode);
        removedCount += redisUtil.del(PREFIX_CODE_AND_DICT_ITEM_MAP + dictCode);

        // STEP Number 返回执行结果
        return removedCount;

    }

    @Override
    public Long batchRemoveSysDictItemCacheGroup(List<String> dictIdList, List<String> dictCodeList) {
        // STEP Number 校验传入参数
        boolean[] checkingResult = checkDictIdListAndDictCodeList(dictIdList, dictCodeList);
        boolean isDictIdListNotEmpty = checkingResult[0];
        boolean isDictCodeListNotEmpty = checkingResult[1];

        // STEP Number 声明相关变量
        long removedCount = 0L;

        // STEP Number 循环执行清理
        if (isDictIdListNotEmpty) {
            for (String dictId : dictIdList) {
                removedCount += removeSysDictItemCacheGroup(dictId, null);

            }

        }
        if (isDictCodeListNotEmpty) {
            for (String dictCode : dictCodeList) {
                removedCount += removeSysDictItemCacheGroup(null, dictCode);

            }

        }

        // STEP Number 返回执行结果
        return removedCount;

    }

    // ===== ===== ===== ===== [实例工具方法] ===== ===== ===== ===== //


    // ===== ===== ===== ===== [静态工具方法] ===== ===== ===== ===== //

    /**
     * 校验传入的字典ID和字典码，若两者同时为空则抛出异常
     *
     * @param dictId   字典ID
     * @param dictCode 字典码
     *
     * @return {@code boolean[]} 校验结果数组，其中
     * <ul>
     *     <li>boolean[0]: isDictIdNotEmpty-字典ID是否不为空</li>
     *     <li>boolean[1]: isDictCodeNotEmpty-字典码是否不为空</li>
     * </ul>
     *
     * @author ZhouYi
     * @date 2020/6/11 17:49
     * @description description
     * @note note
     */
    public static boolean[] checkDictIdAndDictCode(String dictId, String dictCode) {
        // STEP Number 进行基础校验
        boolean[] checkingResult = new boolean[2];
        checkingResult[0] = StringUtils.isNotEmpty(dictId);
        checkingResult[1] = StringUtils.isNotEmpty(dictCode);

        // STEP Number 判断校验结果
        if (!(checkingResult[0]) && !(checkingResult[1])) {
            throw new IllegalArgumentException(I18NUtil.getMsg("sysdict.both.id.and.code.are.blank"));

        }

        // STEP Number 返回校验结果
        return checkingResult;

    }

    /**
     * 校验传入的字典ID列表和字典码列表，若两者同时为空则抛出异常
     *
     * @param dictIdList   字典ID列表
     * @param dictCodeList 字典码列表
     *
     * @return {@code boolean[]} 校验结果数组，其中
     * <ul>
     *     <li>boolean[0]: isDictIdListNotEmpty-字典ID列表是否不为空</li>
     *     <li>boolean[1]: isDictCodeListNotEmpty-字典码列表是否不为空</li>
     * </ul>
     *
     * @author ZhouYi
     * @date 2020/6/11 17:49
     * @description description
     * @note note
     */
    public static boolean[] checkDictIdListAndDictCodeList(List<String> dictIdList, List<String> dictCodeList) {
        // STEP Number 进行基础校验
        boolean[] checkingResult = new boolean[2];
        checkingResult[0] = !(CollectionUtils.isEmpty(dictIdList));
        checkingResult[1] = !(CollectionUtils.isEmpty(dictCodeList));

        // STEP Number 判断校验结果
        if (!(checkingResult[0]) && !(checkingResult[1])) {
            throw new IllegalArgumentException(I18NUtil.getMsg("sysdict.both.id.and.code.are.blank"));

        }

        // STEP Number 返回校验结果
        return checkingResult;

    }

    /**
     * 将对象列表转化为{@link SysDictItem}列表
     *
     * @param objectList 对象列表
     *
     * @return {@code List<SysDictItem>} 转化完毕的{@link SysDictItem}列表
     *
     * @author ZhouYi
     * @date 2020/6/11 18:21
     * @description description
     * @note note
     */
    public static List<SysDictItem> toDictItemList(List<Object> objectList) {
        // STEP Number 校验传入参数
        if (objectList == null) {
            return null;

        }

        // STEP Number 声明相关变量
        List<SysDictItem> dictItemList = new ArrayList<SysDictItem>();

        // STEP Number 循环执行处理
        for (Object obj : objectList) {
            if (obj instanceof SysDictItem) {
                dictItemList.add((SysDictItem) obj);

            }

        }

        // STEP Number 返回处理结果
        return dictItemList;

    }

    /**
     * 将对象Map转化为字符串Map
     *
     * @param objectMap 对象Map
     *
     * @return {@code Map<String,String>} 转化完毕的字符串Map
     *
     * @author ZhouYi
     * @date 2020/6/11 18:27
     * @description description
     * @note note
     */
    public static Map<String, String> toStringMap(Map<Object, Object> objectMap) {
        // STEP Number 校验传入参数
        if (objectMap == null) {
            return null;

        }

        // STEP Number 声明相关变量
        Map<String, String> stringMap = new LinkedHashMap<String, String>();

        // STEP Number 循环执行处理
        for (Map.Entry<Object, Object> entry : objectMap.entrySet()) {
            Object key = entry.getKey();
            Object value = entry.getValue();
            if (key != null) {
                stringMap.put(key.toString(), (value == null) ? null : value.toString());

            }


        }

        // STEP Number 返回处理结果
        return stringMap;

    }

}
